﻿using System.Collections.Generic;

namespace KxParser.Parser.LR
{
    public class ProductionItemEx
    {
        public string Name;
        public List<string> RuleItems = new List<string>();
        public List<string> LookAheadItems = new List<string>(); // For LR(1) parser
        public int DemarkatorPosition;
        public StateEx CurrentState { get; set; }
        public StateEx NextState { get; set; }
        public string OverItem { get; set; }

        public bool IsStarter { get { return Name.Equals(KxParserGlobal.GrammarStarter); } }

        public bool IsEnder { get { return DemarkatorPosition != RuleItems.Count && OverItem.Equals(KxParserGlobal.Ender); } }

        private bool IsDemarkatorOnEnd()
        {
            return DemarkatorPosition == RuleItems.Count;
        }

        public int ContainsRule
        {
            get
            {
                bool equal;

                for (var i = 0; i < KxParserGlobal.ProductionItemsEx.Length; i++)
                {
                    equal = true;

                    //if (Values.Count != Global.ProductionItems[i].Values.Count)
                    if (!IsDemarkatorOnEnd())
                        equal = false;

                    if (RuleItems.Count != KxParserGlobal.ProductionItemsEx[i].RuleItems.Count)
                        equal = false;

                    if (!equal) continue;

                    for (var j = 0; j < RuleItems.Count; j++)
                    {
                        if (RuleItems[j] != KxParserGlobal.ProductionItemsEx[i].RuleItems[j])
                            equal = false;
                    }

                    if (equal)
                        return i;
                }
                return -1;
            }
        }

        public ProductionItemEx(GrammarEx grammar)
        {
			Name = grammar.Name;
			RuleItems.AddRange(grammar.Rule.Split(KxParserGlobal.RuleItemSeparator));

            DemarkatorPosition = 0;
            NextState = null;
            OverItem = KxParserGlobal.Ender;
        }

        public ProductionItemEx(ProductionItemEx productionItem)
        {
			Name = productionItem.Name;
			RuleItems.AddRange(productionItem.RuleItems);

            DemarkatorPosition = productionItem.DemarkatorPosition;
            NextState = null;
            OverItem = KxParserGlobal.Ender;
        }

        public bool CanConsume(string value)
        {
            string nextRuleItem = GetNextRuleItem();
            return (nextRuleItem != null && nextRuleItem.Equals(value));
        }

        public ProductionItemEx Consume(string value)
        {
            if (!CanConsume(value))
                return null;

            ProductionItemEx newProductionItem = new ProductionItemEx(this);
            newProductionItem.DemarkatorPosition++;
            newProductionItem.NextState = null;

            return newProductionItem;
        }

        /// <summary>
        /// Checks if two production items are equal
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (typeof(ProductionItemEx).IsAssignableFrom(obj.GetType()))
            {
                ProductionItemEx pi2 = ((ProductionItemEx)obj);

                if (RuleItems.Count != pi2.RuleItems.Count)
                    return false;

                for (int i = 0; i < RuleItems.Count; i++)
                {
                    if (RuleItems[i] != pi2.RuleItems[i])
                        return false;
                }

                return Name.Equals(pi2.Name) && DemarkatorPosition == pi2.DemarkatorPosition;
            }
            return false;
        }

        /// <summary>
        /// Gets next rule item
        /// </summary>
        /// <returns></returns>
        public string GetNextRuleItem()
        {
            return RuleItems.Count > DemarkatorPosition ? RuleItems[DemarkatorPosition] : null;
        }

        public override string ToString()
        {
            var demarkatorPrinted = false;
            string sRule = string.Empty;
            for (var i = 0; i < RuleItems.Count; i++)
            {
                if (i == DemarkatorPosition)
                {
                    sRule += " " + KxParserGlobal.Demarkator;
                    demarkatorPrinted = true;
                }
                sRule += " " + RuleItems[i];
            }
            if (!demarkatorPrinted)
                sRule += " " + KxParserGlobal.Demarkator;

            string sLookahead = string.Empty;
            foreach (string lookAheadItem in LookAheadItems)
            {
                if (!string.IsNullOrEmpty(sLookahead))
                    sLookahead += ", ";
                sLookahead += lookAheadItem;
            }
            if (string.IsNullOrEmpty(sLookahead))
                sLookahead = KxParserGlobal.Ender;

            return string.Format("[{0}{1}{2}, {3}] ({4}{1}{5}{1}{6}) {7}{8}",Name, KxParserGlobal.Equalator, sRule, sLookahead,
                CurrentState.Id, OverItem, ((NextState != null) ? NextState.Id : -1), (IsStarter) ? KxParserGlobal.ProductionItemStarter : "", (IsEnder) ? KxParserGlobal.ProductionItemEnder : "");
        }
    }
}
